/**
 * HttpClient.java<br>
 *
 * @author aaronwong.sd@foxmail.com
 * @version 下午2:34:39
 */
package com.mc.httpclient;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mc.util.PropertyUtils;

/**
 * http客户端工具
 *
 * @author aaronwong.sd@foxmail.com
 */
public class HttpClient {
	/** logger */
	private static final Logger					logger						= LoggerFactory.getLogger(HttpClient.class);
	private static final HttpClient				instance					= new HttpClient();
	private final HttpRequestRetryHandler		httpRequestRetryHandler		= new HttpRequestRetryHandlerImpl();
	private final ConnectionKeepAliveStrategy	connectionKeepAliveStrategy	= new ConnectionKeepAliveStrategyImpl();
	private PoolingHttpClientConnectionManager	cm							= null;
	private final PropertyUtils					config						= PropertyUtils.getInstance();

	/**
	 * @return the instance
	 */
	public static HttpClient getInstance() {
		return instance;
	}

	private HttpClient() {
		// HTTP
		ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
		// HTTPS
		LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", plainsf)
				.register("https", sslsf).build();
		this.cm = new PoolingHttpClientConnectionManager(registry);
		// 最大连接数
		int maxTotal = this.config.getIntValue("httpclient", "http.client.maxTotal");
		this.cm.setMaxTotal(maxTotal);
		// 每个路由基础的连接
		int maxPerRoute = this.config.getIntValue("httpclient", "http.client.maxPerRoute");
		this.cm.setDefaultMaxPerRoute(maxPerRoute);
		// 超时链接管理
		IdleConnectionMonitorThread idleM = new IdleConnectionMonitorThread(this.cm);
		idleM.start();
		logger.info("### init succeed! Pool maxTotal " + maxTotal + ", defaultMaxPerRoute " + maxPerRoute + ".");
	}

	public CloseableHttpResponse execute(HttpRequestBase request) throws ClientProtocolException, IOException {
		CloseableHttpResponse response = null;
		this.config(request);
		CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).setRetryHandler(this.httpRequestRetryHandler)
				.setKeepAliveStrategy(this.connectionKeepAliveStrategy).build();
		response = httpClient.execute(request, HttpClientContext.create());
		return response;
	}

	/**
	 * 配置http请求
	 *
	 * @param httpRequestBase
	 */
	private void config(HttpRequestBase httpRequestBase) {
		// httpRequestBase.setHeader("User-Agent", "Mozilla/5.0");
		// httpRequestBase.setHeader("Accept",
		// "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		// httpRequestBase.setHeader("Accept-Language",
		// "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
		// httpRequestBase.setHeader("Accept-Charset",
		// "ISO-8859-1,utf-8,gbk,gb2312;q=0.7,*;q=0.7");

		// 配置请求的超时设置
		int connectionRequestTimeout = this.config.getIntValue("httpclient", "http.client.connectionRequestTimeout");
		int connectTimeout = this.config.getIntValue("httpclient", "http.client.connectTimeout");
		int socketTimeout = this.config.getIntValue("httpclient", "http.client.socketTimeout");
		Builder builder = RequestConfig.custom();
		builder.setConnectionRequestTimeout(connectionRequestTimeout * 1000);
		builder.setConnectTimeout(connectTimeout * 1000);
		builder.setSocketTimeout(socketTimeout * 1000);
		httpRequestBase.setConfig(builder.build());
	}
}
